
//-----------------------------------------------------------------------------
//
//Copyright(c) 2020, ThorsianWay Technologies Co, Ltd
//All rights reserved.
//
//IP Name       :   gpu_bus_arbiter
//File Name     :   gpu_bus_arbiter.v
//Module name   :   gpu_bus_arbiter
//Full name     :   gpu bus arbiter
//
//Author        :   xiang tian
//Email         :   
//Data          :   2020/5/5
//Version       :   V1.0
//
//Abstract      :   
//                  
//Called  by    :   gpu bus matrix
//
//Modification history
//-----------------------------------------------------
//1.00: intial version 
//
//
//-----------------------------------------------------------------------------

//-----------------------------
//DEFINE MACRO
//-----------------------------      
module gpu_bus_arbiter #
(
    parameter PORT_NUM = 8,
    parameter PORT_WIDTH = 3
)(
    input                      clk,
    input                      rst_n,
    input                      en,
    input      [PORT_NUM-1:0]  req,
    output     [PORT_NUM-1:0]  gnt,
    output reg [PORT_WIDTH-1:0]sel,
    output     [PORT_NUM-1:0]  gnt_latch,
    output     [PORT_WIDTH-1:0]sel_latch
);

reg  [PORT_NUM-1:0]   base;
reg  [PORT_NUM-1:0]   gnt_ff;
reg  [PORT_WIDTH-1:0] sel_ff;
reg  [PORT_WIDTH-1:0] sel_inter;

wire [2*PORT_NUM-1:0] double_req = {req,req};
wire [2*PORT_NUM-1:0] double_grant = double_req & ~(double_req - base);
wire [PORT_NUM-1:0]   grant = double_grant[PORT_NUM-1:0] | double_grant[PORT_NUM*2-1:PORT_NUM];

wire round_en = en && (|req);

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)  base <= 1;
    else if(round_en) base <= {base[PORT_NUM-2:0],base[PORT_NUM-1]};

end                


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)  gnt_ff <= {PORT_NUM{1'b0}};
    else if(en) gnt_ff <= grant;

end


assign gnt = en ? grant : 0;
assign gnt_latch = en ? grant : gnt_ff;

integer i;

always @*
begin
    sel = 0;
    for(i=0;i<PORT_NUM;i=i+1)
    begin
        if(gnt[i]==1'b1) sel = i;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)  sel_ff <= {PORT_NUM{1'b0}};
    else if(en) sel_ff <= sel;
end 

assign sel_latch = en ? sel : sel_ff;

endmodule
